package com.example.test;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class SimpleIOC {
    // 存储Bean的容器：key=beanId，value=Bean实例
    private final Map<String, Object> beanMap = new HashMap<>();

    /**
     * 构造方法：加载XML配置，初始化Bean容器
     * @param xmlPath resources下的XML路径（如"beans.xml"）
     */
    public SimpleIOC(String xmlPath) {
        try {
            // 1. 加载XML文件（通过类加载器获取资源流）
            InputStream is = getClass().getClassLoader().getResourceAsStream(xmlPath);
            // 2. JDK原生XML解析：创建Document对象（XML内存树）
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new InputSource(is));

            // 3. 解析根节点<beans>下的所有<bean>标签
            Element root = doc.getDocumentElement();
            NodeList beanNodes = root.getElementsByTagName("bean");

            // 4. 遍历每个<bean>，创建实例并注入属性
            for (int i = 0; i < beanNodes.getLength(); i++) {
                Element beanEle = (Element) beanNodes.item(i);
                createAndRegisterBean(beanEle);
            }

            is.close(); // 关闭输入流
        } catch (Exception e) {
            throw new RuntimeException("IOC容器初始化失败", e);
        }
    }

    /**
     * 解析单个<bean>标签：创建Bean实例 + 注入属性 + 注册到容器
     */
    private void createAndRegisterBean(Element beanEle) throws Exception {
        // 1. 获取Bean的id和全类名
        String beanId = beanEle.getAttribute("id");
        String className = beanEle.getAttribute("class");

        // 2. 反射加载类并创建实例（依赖无参构造）
        Class<?> beanClass = Class.forName(className);
        Object beanInstance = beanClass.newInstance();

        // 3. 解析<property>标签，注入属性（通过Setter方法）
        NodeList propNodes = beanEle.getElementsByTagName("property");
        for (int i = 0; i < propNodes.getLength(); i++) {
            Element propEle = (Element) propNodes.item(i);
            String propName = propEle.getAttribute("name"); // 属性名（如id、name）
            String propValue = propEle.getAttribute("value"); // 属性值（字符串）

            // 3.1 生成Setter方法名：set + 首字母大写的属性名（如setId、setName）
            String setterName = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
            // 3.2 确定Setter方法的参数类型（根据属性值判断：String/int/double）
            Class<?> paramType = getParamType(propValue);
            // 3.3 获取Setter方法并调用（注入转换后的值）
            Method setterMethod = beanClass.getMethod(setterName, paramType);
            Object convertedValue = convertValue(propValue, paramType);
            setterMethod.invoke(beanInstance, convertedValue);
        }

        // 4. 将Bean实例注册到容器
        beanMap.put(beanId, beanInstance);
    }

    /**
     * 根据属性值判断参数类型（简化版：仅支持String/int/double）
     */
    private Class<?> getParamType(String value) {
        if (value.matches("^\\d+$")) { // 纯数字 → int
            return int.class;
        } else if (value.matches("^\\d+\\.\\d+$")) { // 带小数点 → double
            return double.class;
        } else { // 其他 → String
            return String.class;
        }
    }

    /**
     * 将字符串值转为目标类型（String/int/double）
     */
    private Object convertValue(String value, Class<?> targetType) {
        if (targetType == String.class) {
            return value;
        } else if (targetType == int.class) {
            return Integer.parseInt(value);
        } else if (targetType == double.class) {
            return Double.parseDouble(value);
        }
        throw new RuntimeException("不支持的类型：" + targetType.getName());
    }

    /**
     * 对外提供获取Bean的方法（模仿Spring的getBean）
     */
    public Object getBean(String beanId) {
        Object bean = beanMap.get(beanId);
        if (bean == null) {
            throw new RuntimeException("容器中无此Bean：" + beanId);
        }
        return bean;
    }
}
